#include "value_option.h"

CValueOption::CValueOption(int nIndex, const string &szOptionText)
    : COption(nIndex, szOptionText)
{
    /**
     * Constructor, initialise the option and store the initial value for
     * the option held by this class.
     * 
     * @param int nIndex The index of the option
     * @param string szOptionText The text of option
     * @param utils::PARAM param The initial value of the text
     */
    m_Value.vpValue = nullptr;
    m_Value.nType = utils::TYPE_OTHER;
    m_Value.nDereferenceSize = 0;
    setActive(false);
}


CValueOption::CValueOption(int nIndex, const string &szOptionText, 
    const utils::PARAM &param)
    : COption(nIndex, szOptionText),
    m_Value(param)
{
    /**
     * Constructor, initialise the option and store the initial value for
     * the option held by this class.
     * 
     * @param int nIndex The index of the option
     * @param string szOptionText The text of option
     * @param utils::PARAM param The initial value of the text
     */
    setActive(false);
}

void CValueOption::setFunction(void (*pFunction)(CMenu *, COption *, 
    DELAY_PARAMS &, utils::PARAM &param, unsigned char chKey))
{
    /**
     * @param functionptr The callback function to call when when the option
     *  has been selected.
     */
    m_pFunctionPtr = pFunction;
}

void CValueOption::callFunction(CMenu *pMenu, unsigned char chKey)
{
    /**
     * Calls the option that is currently selected.
     */
    m_pFunctionPtr(pMenu, this, m_arrParams, m_Value, chKey);
}

void CValueOption::setActive(bool bActive)
{
    /**
     * Sets the active state of the value option to a new value. Changing the
     * state changes the text to hold a new representation. This string 
     * representation should be either a - or a blank space before the text
     * to simulate a highlighted option, and then the value of the option after.
     * The value is taken from the type of the void pointer, cast, and 
     * turned to a string representation.
     * 
     * @param bool bActive Whether or not the new active state of the option
     *  is active.
     */
    stringstream sstream;
    sstream << (bActive ? "- " : "  ")
            << getOriginalText()
            << " ";
    if (m_Value.vpValue != nullptr)
    {
        switch (m_Value.nType)
        {
            case utils::TYPE_BOOL:
            {
                if (*(reinterpret_cast<bool*>(m_Value.vpValue)))
                {
                    sstream << "On";
                }
                else
                {
                    sstream << "Off";
                }
                break;
            }

            case (utils::TYPE_SLONG):
            {
                sstream << *(reinterpret_cast<signed long*>(m_Value.vpValue));
                break;
            }

            case (utils::TYPE_SSHORT):
            {
                sstream << *(reinterpret_cast<signed short*>(m_Value.vpValue));
                break;
            }

            case (utils::TYPE_ULONG):
            {
                sstream << *(reinterpret_cast<unsigned long*>(m_Value.vpValue));
                break;
            }

            case (utils::TYPE_USHORT):
            {
                sstream << *(reinterpret_cast<unsigned short*>(
                    m_Value.vpValue));
                break;
            }

            case (utils::TYPE_FLOAT):
            {
                sstream << std::setw(2)
                        << std::setprecision(3)
                        << *(reinterpret_cast<float*>(m_Value.vpValue));
                break;
            }

            case (utils::TYPE_DOUBLE):
            {
                sstream << std::setw(2)
                    << std::setprecision(3)
                    << *(reinterpret_cast<double*>(m_Value.vpValue));
                break;
            }

            case (utils::TYPE_STRING):
            {
                char szBuffer[128];
                strncpy(szBuffer, reinterpret_cast<char*>(m_Value.vpValue),
                    m_Value.nDereferenceSize);
                szBuffer[m_Value.nDereferenceSize] = '\0';
                sstream << szBuffer;
                break;
            }

            default:
            {
                sstream << "?";
                break;
            }
        }
    }

    setText(sstream.str());

    float fRed, fGreen, fBlue, fAlpha;
    if (bActive)
    {
        getInactiveColour(fRed, fGreen, fBlue, fAlpha);
    }
    else
    {
        getActiveColour(fRed, fGreen, fBlue, fAlpha);
    }
    setColour(fRed, fGreen, fBlue, fAlpha);

    m_bActive = bActive;
}